<!DOCTYPE HTML>
<html>
<head>
  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
  <script type="application/javascript" src="head.js"></script>
</head>
<body>
<pre id="test">
<script>

createHTML({
  bug: "1259788",
  title: "Test CaptureStream track output on HTMLMediaElement playing a gUM MediaStream",
  visible: true
});

var audioElement;
var audioCaptureStream;
var videoElement;
var videoCaptureStream;
var untilEndedElement;
var streamUntilEnded;
var tracks = [];
runTest(() => getUserMedia({audio: true, video: true})
  .then(stream => {
    // We need to test with multiple tracks. We add an extra of each kind.
    stream.getTracks().forEach(t => stream.addTrack(t.clone()));

    audioElement = createMediaElement("audio", "gUMAudio");
    audioElement.srcObject = stream;

    return haveEvent(audioElement, "loadedmetadata", wait(50000, new Error("Timeout")));
  })
  .then(() => {
    info("Capturing audio element (loadedmetadata -> captureStream)");
    audioCaptureStream = audioElement.mozCaptureStream();

    is(audioCaptureStream.getAudioTracks().length, 2,
       "audio element should capture two audio tracks");
    is(audioCaptureStream.getVideoTracks().length, 0,
       "audio element should not capture any video tracks");

    return haveNoEvent(audioCaptureStream, "addtrack");
  })
  .then(() => {
    videoElement = createMediaElement("video", "gUMVideo");

    info("Capturing video element (captureStream -> loadedmetadata)");
    videoCaptureStream = videoElement.mozCaptureStream();
    videoElement.srcObject = audioElement.srcObject.clone();

    is(videoCaptureStream.getTracks().length, 0,
       "video element should have no tracks before metadata known");

    return haveEventsButNoMore(
        videoCaptureStream, "addtrack", 3, wait(50000, new Error("No event")));
  })
  .then(() => {
    is(videoCaptureStream.getAudioTracks().length, 2,
       "video element should capture two audio tracks");
    is(videoCaptureStream.getVideoTracks().length, 1,
       "video element should capture one video track at most");

    info("Testing dynamically adding audio track to audio element");
    audioElement.srcObject.addTrack(
        audioElement.srcObject.getAudioTracks()[0].clone());
    return haveEventsButNoMore(
        audioCaptureStream, "addtrack", 1, wait(50000, new Error("No event")));
  })
  .then(() => {
    is(audioCaptureStream.getAudioTracks().length, 3,
       "Audio element should have three audio tracks captured.");

    info("Testing dynamically adding video track to audio element");
    audioElement.srcObject.addTrack(
        audioElement.srcObject.getVideoTracks()[0].clone());
    return haveNoEvent(audioCaptureStream, "addtrack");
  })
  .then(() => {
    is(audioCaptureStream.getVideoTracks().length, 0,
       "Audio element should have no video tracks captured.");

    info("Testing dynamically adding audio track to video element");
    videoElement.srcObject.addTrack(
        videoElement.srcObject.getAudioTracks()[0].clone());
    return haveEventsButNoMore(
        videoCaptureStream, "addtrack", 1, wait(50000, new Error("Timeout")));
  })
  .then(() => {
    is(videoCaptureStream.getAudioTracks().length, 3,
       "Captured video stream should have three audio tracks captured.");

    info("Testing dynamically adding video track to video element");
    videoElement.srcObject.addTrack(
        videoElement.srcObject.getVideoTracks()[0].clone());
    return haveNoEvent(videoCaptureStream, "addtrack");
  })
  .then(() => {
    is(videoCaptureStream.getVideoTracks().length, 1,
       "Captured video stream should have at most one video tracks captured.");

    info("Testing track removal.");
    tracks.push(...videoElement.srcObject.getTracks());
    videoElement.srcObject.getVideoTracks().reverse().forEach(t =>
        videoElement.srcObject.removeTrack(t));
    is(videoCaptureStream.getVideoTracks()
                         .filter(t => t.readyState == "live").length, 1,
       "Captured video should have still have one video track captured.");

    return haveEvent(videoCaptureStream.getVideoTracks()[0], "ended",
                     wait(50000, new Error("Timeout")));
  })
  .then(() => {
    is(videoCaptureStream.getVideoTracks()
                         .filter(t => t.readyState == "live").length, 0,
       "Captured video stream should have no video tracks captured after removal.");

    info("Testing source reset.");
  })
  .then(() => getUserMedia({audio: true, video: true}))
  .then(stream => {
    videoElement.srcObject = stream;
    return Promise.all(videoCaptureStream.getTracks()
        .filter(t => t.readyState == "live")
        .map(t => haveEvent(t, "ended", wait(50000, new Error("Timeout")))));
  })
  .then(() => haveEventsButNoMore(
                  videoCaptureStream, "addtrack", 2, wait(50000, new Error("Timeout"))))
  .then(() => {
    is(videoCaptureStream.getAudioTracks()
        .filter(t => t.readyState == "ended").length, 3,
       "Captured video stream should have three ended audio tracks");
    is(videoCaptureStream.getAudioTracks()
        .filter(t => t.readyState == "live").length, 1,
       "Captured video stream should have one live audio track");

    is(videoCaptureStream.getVideoTracks()
        .filter(t => t.readyState == "ended").length, 1,
       "Captured video stream should have one ended video tracks");
    is(videoCaptureStream.getVideoTracks()
        .filter(t => t.readyState == "live").length, 1,
       "Captured video stream should have one live video track");

    info("Testing CaptureStreamUntilEnded");
    untilEndedElement =
      createMediaElement("video", "gUMVideoUntilEnded");
    untilEndedElement.srcObject = audioElement.srcObject;

    return haveEvent(untilEndedElement, "loadedmetadata",
                     wait(50000, new Error("Timeout")));
  })
  .then(() => {
    streamUntilEnded = untilEndedElement.mozCaptureStreamUntilEnded();

    is(streamUntilEnded.getAudioTracks().length, 3,
       "video element should capture all 3 audio tracks until ended");
    is(streamUntilEnded.getVideoTracks().length, 1,
       "video element should capture only 1 video track until ended");

    untilEndedElement.srcObject.getTracks().forEach(t => t.stop());
    // TODO(1208316) We stop the stream to make the media element end.
    untilEndedElement.srcObject.stop();

    return Promise.all([
      haveEvent(untilEndedElement, "ended", wait(50000, new Error("Timeout"))),
      ...streamUntilEnded.getTracks()
           .map(t => haveEvent(t, "ended", wait(50000, new Error("Timeout"))))
    ]);
  })
  .then(() => {
    info("Element and tracks ended. Ensuring that new tracks aren't created.");
    untilEndedElement.srcObject = videoElement.srcObject;
    return haveEventsButNoMore(
        untilEndedElement, "loadedmetadata", 1, wait(50000, new Error("Timeout")));
  })
  .then(() => is(streamUntilEnded.getTracks().length, 4,
                 "Should still have 4 tracks"))
  .catch(e => ok(false, "Test failed: " + e + (e && e.stack ? "\n" + e.stack : "")))
  .then(() => [...tracks,
               ...videoElement.srcObject.getTracks()].forEach(t => t.stop())));

</script>
</pre>
</body>
</html>
